package com.xinghai.web.controller.dingtalk;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
import com.dingtalk.open.app.api.models.bot.MessageContent;
import com.xinghai.common.annotation.Log;
import com.xinghai.common.core.controller.BaseController;
import com.xinghai.common.core.domain.AjaxResult;
import com.xinghai.common.enums.BusinessType;
import com.xinghai.common.exception.ServiceException;
import com.xinghai.common.utils.DateUtils;
import com.xinghai.common.utils.StringUtils;
import com.xinghai.common.utils.poi.ExcelUtil;
import com.xinghai.framework.config.ServerConfig;
import com.xinghai.system.domain.*;
import com.xinghai.system.domain.dto.*;
import com.xinghai.system.domain.vo.*;
import com.xinghai.system.service.*;
import com.xinghai.system.util.XHConstant;
import com.xinghai.web.controller.dingtalk.dto.DingCallbackCrypto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 钉钉OA
 *
 * @author xinghai
 */
@Slf4j
@RestController
@RequestMapping("/api/dingtalk")
public class DingdingOaController extends BaseController {

    @Autowired
    private DingdingOaService dingdingOaService;
    @Autowired
    private IXhUseVehicleInfoService xhUseVehicleInfoService;
    @Autowired
    private IXhVehicleInfoMaterialService xhVehicleInfoMaterialService;
    @Autowired
    private ISysNoticeService sysNoticeService;
    @Autowired
    private IXhVehicleOrderInfoService xhVehicleOrderInfoService;
    @Autowired
    private IXhVehicleInfoApplyRecordService xhVehicleInfoApplyRecordService;

    @Value("${dingtalk.token}")
    private String token;
    @Value("${dingtalk.encodingAesKey}")
    private String encodingAesKey;
    @Value("${dingtalk.corpId}")
    private String corpId;
    @Value("${dingtalk.contract.url}")
    private String url;

    @Autowired
    private ISysDictDataService sysDictDataService;

    @GetMapping("/getDingUserList")
    public AjaxResult list(@RequestParam(value = "mobile", required = false) String mobile) {
        List<DingUser> list = dingdingOaService.getDingUserList(mobile);
        return success(list);
    }

    @Autowired
    private ServerConfig serverConfig;


    @PostMapping("/getNotifity")
    public Map<String, String> list(@RequestParam(value = "msg_signature", required = false) String msg_signature,
                                    @RequestParam(value = "timestamp", required = false) String timeStamp,
                                    @RequestParam(value = "nonce", required = false) String nonce,
                                    @RequestBody(required = false) JSONObject json) {
        System.out.println(json);

        try {
            // 1. 从http请求中获取加解密参数
            // 2. 使用加解密类型
            // 2、调用订阅事件接口订阅的事件为企业级事件推送，此时OWNER_KEY为：开发者后台应用的Client ID（原企业内部应用 appKey )
            DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(token,
                    encodingAesKey,
                    corpId);
            String encryptMsg = json.getString("encrypt");
            String decryptMsg = callbackCrypto.getDecryptMsg(msg_signature, timeStamp, nonce, encryptMsg);
            //判断是否进入消息
            JSONObject jsonObject = JSON.parseObject(decryptMsg);
            logger.info("==========解析后的推送数据=BEGIN========");
            logger.info("[{}]", jsonObject);
            logger.info("==========解析后的推送数据=END========");
            //推送消息到用车申请主表
            xhUseVehicleInfoService.receiveDingMsg(jsonObject);
            String resource = jsonObject.getString("resource");
            String activityName = jsonObject.getString("activityName");
            String instanceId = jsonObject.getString("processInstanceId");
            String type = jsonObject.getString("type");
            try {
                //节点中文名称
                if (StringUtils.equals(activityName, sysDictDataService.selectDictLabel("point_type", StringPool.ONE))) {
                    //质检员确认后 => 系统自动分配物流公司
                    dingdingOaService.dispatchVehicle(instanceId);
                }

                if (StringUtils.equals(activityName, sysDictDataService.selectDictLabel("point_type", XHConstant.STR_9))
                        && XHConstant.DING_MSG_FINISH.equals(type)) {
                    //项目经理到货审批后 => 确认是否产生品质损失
                    // type => finish
                    dingdingOaService.genQualityLoss(instanceId, type, activityName);
                }

            } catch (Exception e) {
                log.error("[{}]", e.getMessage());
            }
            //站内信
            if (StringUtils.endsWith(resource, "cancel")) {
                //驳回审批
//                dingdingOaService.addNotice(decryptMsg, true);
                //查询数据源
                XhUseVehicleInfo vehicleInfo = xhUseVehicleInfoService.selectInfoByInstanceId(instanceId);
                XhVehicleOrderInfo orderInfo = xhVehicleOrderInfoService.lambdaQuery().eq(XhVehicleOrderInfo::getVehicleId, vehicleInfo.getId()).last(" limit 1").one();
                orderInfo.setRemark(jsonObject.getString("remark"));
                xhVehicleOrderInfoService.updateById(orderInfo);
            }
            if (StringUtils.endsWith(resource, "start")) {
                //正常审批
                if (StringUtils.equals(activityName, sysDictDataService.selectDictLabel("point_type", XHConstant.STR_1))) {
                    //查询数据源
                    XhUseVehicleInfo vehicleInfo = xhUseVehicleInfoService.selectInfoByInstanceId(instanceId);
                    XhVehicleOrderInfo orderInfo = xhVehicleOrderInfoService.lambdaQuery().eq(XhVehicleOrderInfo::getVehicleId, vehicleInfo.getId()).last(" limit 1").one();
                    //是否首次派车
                    Long recordCount = xhVehicleInfoApplyRecordService.lambdaQuery()
                            .eq(XhVehicleInfoApplyRecord::getVehicleId, vehicleInfo.getId())
                            .eq(XhVehicleInfoApplyRecord::getActivityName, activityName).count();
                    //拼接消息
                    SysNotice notice = new SysNotice();
                    notice.setInstanceId(instanceId);
                    notice.setDeptId(orderInfo.getDeptId());
                    //物流公司
                    notice.setCompanyType(Integer.valueOf(XHConstant.STR_0));
                    if (recordCount > 1) {
                        //待承接单
                        notice.setRedUrl(XHConstant.STR_4);
                        //标题
                        notice.setNoticeTitle("您有被退回用车任务，请查收。");
                        //内容
                        notice.setNoticeContent("用车任务【" + vehicleInfo.getProjectName() + "】，于" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", orderInfo.getUpdateTime()) + "被退回，请到【待审批承运单】进行车辆变更操作。");
                    } else {
                        //待承接单
                        notice.setRedUrl(XHConstant.STR_3);
                        //标题
                        notice.setNoticeTitle("您有新的待承接物用车任务，请查收。");
                        //内容
                        notice.setNoticeContent("用车任务【" + vehicleInfo.getProjectName() + "】，于" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", orderInfo.getCreateTime()) + "由系统自动派发，请到【待接承运单】进行接单操作。");
                    }
                    sysNoticeService.addNotice(notice);
                }
            }
            // 3. 反序列化回调事件json数据
            JSONObject eventJson = JSON.parseObject(decryptMsg);
            String eventType = eventJson.getString("EventType");

            // 4. 根据EventType分类处理
            if ("check_url".equals(eventType)) {
                // 测试回调url的正确性
//                bizLogger.info("测试回调url的正确性");
            } else if ("user_add_org".equals(eventType)) {
                // 处理通讯录用户增加事件
//                bizLogger.info("发生了：" + eventType + "事件");
            } else {
                // 添加其他已注册的
//                bizLogger.info("发生了：" + eventType + "事件");
            }

            // 5. 返回success的加密数据
            Map<String, String> successMap = callbackCrypto.getEncryptedMap("success");
            return successMap;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @PostMapping("/redirectVehicle")
    public AjaxResult redirectVehicle(@RequestBody XhVehicleOrderInfoDTO xhVehicleOrderInfoDTO) throws MalformedURLException {
//        System.out.println("----------------------------"+xhVehicleOrderInfoDTO.getId()+"------------------------"+xhVehicleOrderInfoDTO.getDeptId()+ xhVehicleOrderInfoDTO.getAssignType());
        dingdingOaService.redirectVehicle(xhVehicleOrderInfoDTO, getUsername());
        return success();
    }

    @PostMapping("/createFlow")
    public AjaxResult createFlow(@RequestParam("id") Long id) throws MalformedURLException {
        return success(dingdingOaService.createFlow(id));
    }

    @PostMapping("/addComments")
    public AjaxResult addComments(@RequestParam("id") Long id) throws MalformedURLException {
        try {
            dingdingOaService.addComments(id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return success(true);
    }

    @PostMapping("/approvalFlow")
    public AjaxResult approvalFlow(@RequestBody DingApprovalResDTO dingApprovalResDTO) throws MalformedURLException {
        return success(dingdingOaService.approvalFlow(dingApprovalResDTO));
    }


    /**
     * 获取登录凭证
     * #193540318
     *
     * @return
     */
    @GetMapping("/gettoken")
    public AjaxResult gettoken() {
        return success(dingdingOaService.getToken());
    }


    /**
     * 机器人AI单聊
     *
     * @param message
     * @return
     */
    @PostMapping("/sendRobot")
    public AjaxResult sendRobot(@RequestBody ChatbotMessage message) {
        try {
            MessageContent text = message.getText();
            String userId = message.getSenderStaffId();
            if (text != null) {
                String msg = text.getContent();
                log.info("receive bot message from user={}, msg={}", userId, msg);
                try {
                    //发送机器人消息
                    return success(dingdingOaService.send(msg, userId));
                } catch (Exception e) {
                    log.error("send private message by robot error:" + e.getMessage(), e);
                }
            }
        } catch (Exception e) {
            log.error("receive private message by robot error:" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 主动同步组织架构内部门列表
     *
     * @return
     */
    @GetMapping("/department/list")
    public AjaxResult departmentList() {
        List<DingTalkDeptVo> dingTalkDeptVos = dingdingOaService.departmentList();
        //保存组织
        dingdingOaService.saveCollection(dingTalkDeptVos);
        return success(dingTalkDeptVos);
    }


    /**
     * 主动同步组织架构内用户列表
     *
     * @return
     */
    @GetMapping("/department/users")
    public AjaxResult getUserDepartmentList(@RequestParam("departmentId") String departmentId) {
        List<DingTalkUserVo> userDepartmentList = dingdingOaService.getUserDepartmentList(departmentId);
        //保存组织
        dingdingOaService.saveCollection(userDepartmentList);
        return success(userDepartmentList);
    }

    /**
     * 主动同步部门成员信息
     *
     * @return
     */
    @GetMapping("/department/all")
    public AjaxResult all() {
        try {
            List<DingTalkDeptVo> dingTalkDeptVos = dingdingOaService.departmentList();
            dingdingOaService.saveCollection(dingTalkDeptVos);
            dingTalkDeptVos.stream().forEach(it -> {
                dingdingOaService.recursionDeptList(it);
//                dingdingOaService.saveCollection(dingdingOaService.getUserDepartmentList(it.getDept_id()));
            });
        } catch (Exception e) {
            log.error("=====同步部门成员信息error:{}=====", e.getMessage());
            return error("同步失败,请联系管理员！");
        }
        return success(true);
    }

    /**
     * 获取钉钉组织架构
     *
     * @return
     */
    @GetMapping("/getSyNcOrganizational")
    public AjaxResult getSyNcOrganizational() {
        return success(dingdingOaService.getSyNcOrganizational());
    }

    /**
     * 获取本地存储的钉钉组织架构
     *
     * @return
     */
    @GetMapping("/getLocalOrganizational")
    public AjaxResult getLocalOrganizational() {
        return success(dingdingOaService.getLocalList());
    }

    /**
     * 2.0新项目需求发起
     *
     * @return
     */
    @PostMapping("/mode/v2/initiate")
    public AjaxResult initiate(@RequestBody XhVehicleInfoDTO dto) {
        return success(dingdingOaService.initiate(dto));
    }


    /**
     * 根据手机号查询用户
     *
     * @return
     */
    @GetMapping("/getUserByPhone")
    public AjaxResult getUserByPhone(@RequestParam(required = false, value = "mobile") String mobile) {
        return success(dingdingOaService.getUserByPhone(mobile));
    }

    /**
     * 2.0根据流程id查询流程内容
     *
     * @return
     */
    @GetMapping("/mode/v1/workflow/processInstances")
    public AjaxResult getWorkflowByProcessInstancesId(String processInstanceId) throws Exception {
        return success(dingdingOaService.getWorkflowByProcessInstancesId(processInstanceId));
    }


    /**
     * 创建动态合同
     *
     * @param request
     * @return
     */
    @PostMapping("/mode/v1/createContract")
    public AjaxResult createContract(@RequestBody CreateContractRequestVo request) {
        request.setUrl(serverConfig.getUrl());
        String url = null;
        try {
            url = dingdingOaService.createContract(request);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        return success(url);
    }

    /**
     * 2.0根据流程id撤销流程
     *
     * @return
     */
    @PostMapping("/mode/v1/workflow/processInstances/terminate")
    public AjaxResult cancelWorkflowByProcessInstancesId(@RequestBody Map<String, String> cancelVO) throws Exception {
        return success(dingdingOaService.cancelWorkflowByProcessInstancesId(cancelVO));
    }

    /** ============================== 耗材明细相关接口-开始 ============================== **/

    /**
     * 查询用车任务的耗材明细
     *
     * @return
     */
    @GetMapping("/getUrlPath/{type}/{vehicleId}")
    public AjaxResult getUrlPathToMaterial(@PathVariable("type") String type, @PathVariable("vehicleId") String vehicleId) {
        return success(dingdingOaService.getUrlPathToMaterial(type, vehicleId));
    }

    /**
     * 查询用车耗材明细列表
     */
    @GetMapping("/list/by/type/and/vehicleId")
    public AjaxResult getListByTypeAndVehicleId(XhVehicleInfoMaterial xhVehicleInfoMaterial) {
        List<XhVehicleInfoMaterial> list = xhVehicleInfoMaterialService.lambdaQuery()
                .eq(StringUtils.isNotNull(xhVehicleInfoMaterial.getVehicleId()), XhVehicleInfoMaterial::getVehicleId, xhVehicleInfoMaterial.getVehicleId())
                .eq(StringUtils.isNotNull(xhVehicleInfoMaterial.getType()), XhVehicleInfoMaterial::getType, xhVehicleInfoMaterial.getType())
                .eq(XhVehicleInfoMaterial::getDelFlag, XHConstant.DEL_FLAG_NORMAL)
                .orderByAsc(XhVehicleInfoMaterial::getCreateTime)
                .list();
        return success(list);
    }

    /**
     * 批量保存耗材明细列表
     */
    @PostMapping("/save/batch/material")
    public AjaxResult saveBatchMaterial(@RequestBody XhVehicleInfoMaterialVO xhVehicleInfoMaterialVO) {
        return success(xhVehicleInfoMaterialService.saveBatchMateial(xhVehicleInfoMaterialVO));
    }

    /** ============================== 耗材明细相关接口-结束 ============================== **/

    /**
     * 下载生成的合同模板
     *
     * @param id
     * @return
     */
    @GetMapping("/download/contract")
    public AjaxResult downloadContract(@RequestParam("id") Long id) {
        return AjaxResult.success(dingdingOaService.downloadContract(id));
    }

    /**
     * 废弃 测试品质损失保存
     *
     * @param id
     * @return
     */
    @Deprecated
    @GetMapping("/test/pz/{instanceId}")
    public AjaxResult testPz(@PathVariable("instanceId") String id) {
        dingdingOaService.genQualityLoss(id, null, null);
        return AjaxResult.success();
    }

    /**
     * 根据钉钉回调code获取授权用户的个人信息
     *
     * @return
     */
    @GetMapping("/test/login")
    public AjaxResult getPwScan(@RequestParam("code") String code, HttpServletResponse response) {
        AjaxResult ajax = null;
        try {
            // 通过临时授权码获取授权用户的个人信息
            ajax = AjaxResult.success();
            String userName = dingdingOaService.getPwScan(code);
            //登录账号获取登录token
//            String token = loginService.login(userName);
//            ajax.put(Constants.TOKEN, token);
            response.sendRedirect(url + "initiate?mobile=" + userName);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return ajax;
    }

    /**
     * 测试创建待办
     *
     * @return
     */
    @Deprecated
    @PostMapping("/test/createPlan")
    public AjaxResult createPlan(@RequestBody DingTalkTodoDTO dto) {
        // 通过临时授权码获取授权用户的个人信息
        return AjaxResult.success(dingdingOaService.createPlan(dto));
    }

    /**
     * 获取企业用户的unionid
     *
     * @return
     */
    @GetMapping("/test/getUnionid")
    public AjaxResult getUnionid(@RequestParam("userId") String userId) {
        // 通过userid查询unionid
        return AjaxResult.success(dingdingOaService.getUnionid(userId));
    }

    /**
     * 导出用车耗材需求人明细模板
     */
    @Log(title = "导出需求人明细模板", businessType = BusinessType.EXPORT)
    @PostMapping("/need/user/export")
    public void needUserExport(HttpServletResponse response, XhVehicleInfoMaterial xhVehicleInfoMaterial) {
        List<XhVehicleInfoMaterialNeedDTO> list = new ArrayList<>();
        String sheetName = "用车耗材需求人明细模板";
        if (xhVehicleInfoMaterial.getVehicleId() != null && XHConstant.MATERIAL_STATUS_NEED.equals(xhVehicleInfoMaterial.getType())) {
            List<XhVehicleInfoMaterial> materialList = xhVehicleInfoMaterialService.list(xhVehicleInfoMaterial);
            if (Objects.nonNull(materialList) && materialList.size() > 0) {
                for (XhVehicleInfoMaterial material : materialList) {
                    XhVehicleInfoMaterialNeedDTO materialInfo = new XhVehicleInfoMaterialNeedDTO();
                    BeanUtils.copyProperties(material, materialInfo);
                    list.add(materialInfo);
                }
            }
            sheetName = "用车耗材需求人明细";
        }
        ExcelUtil<XhVehicleInfoMaterialNeedDTO> util = new ExcelUtil<XhVehicleInfoMaterialNeedDTO>(XhVehicleInfoMaterialNeedDTO.class);
        util.exportExcel(response, list, sheetName);
    }

    /**
     * 导出用车耗材装车人明细模板
     */
    @Log(title = "导出装车人明细模板", businessType = BusinessType.EXPORT)
    @PostMapping("/puck/user/export")
    public void puckUserExport(HttpServletResponse response, XhVehicleInfoMaterial xhVehicleInfoMaterial) {
        List<XhVehicleInfoMaterialPuckDTO> list = new ArrayList<>();
        String sheetName = "用车耗材装车人明细模板";
        if (xhVehicleInfoMaterial.getVehicleId() != null && XHConstant.MATERIAL_STATUS_PUCK.equals(xhVehicleInfoMaterial.getType())) {
            List<XhVehicleInfoMaterial> materialList = xhVehicleInfoMaterialService.list(xhVehicleInfoMaterial);
            if (Objects.nonNull(materialList) && materialList.size() > 0) {
                for (XhVehicleInfoMaterial material : materialList) {
                    XhVehicleInfoMaterialPuckDTO materialInfo = new XhVehicleInfoMaterialPuckDTO();
                    BeanUtils.copyProperties(material, materialInfo);
                    list.add(materialInfo);
                }
            }
            sheetName = "用车耗材装车人明细";
        }
        ExcelUtil<XhVehicleInfoMaterialPuckDTO> util = new ExcelUtil<XhVehicleInfoMaterialPuckDTO>(XhVehicleInfoMaterialPuckDTO.class);
        util.exportExcel(response, list, sheetName);
    }

    /**
     * 导入用车耗材需求人/装车人明细明细
     */
    @Log(title = "用车耗材明细管理", businessType = BusinessType.IMPORT)
    @PostMapping("/importMaterial")
    public AjaxResult importMaterial(MultipartFile file, String vehicleId, String type) {
        List<XhVehicleInfoMaterial> list = new ArrayList<>();
        List<XhVehicleInfoMaterialNeedDTO> needList = null;
        List<XhVehicleInfoMaterialPuckDTO> puckList = null;
        if (XHConstant.MATERIAL_STATUS_NEED.equals(type)) {
            //需求人
            ExcelUtil<XhVehicleInfoMaterialNeedDTO> util = new ExcelUtil<XhVehicleInfoMaterialNeedDTO>(XhVehicleInfoMaterialNeedDTO.class);
            try {
                needList = util.importExcel(file.getInputStream());
                if (needList.size() < 1) {
                    return error("上传的表格内无数据");
                }
            } catch (IOException e) {
                throw new ServiceException("导入数据失败");
            }
            for (XhVehicleInfoMaterialNeedDTO needDTO : needList) {
                XhVehicleInfoMaterial material = convertToMaterialInfo(needDTO, vehicleId, type);
                material.setCreateTime(DateUtils.getNowDate());
                list.add(material);
            }
        } else if (XHConstant.MATERIAL_STATUS_PUCK.equals(type)) {
            //装车人
            ExcelUtil<XhVehicleInfoMaterialPuckDTO> util = new ExcelUtil<XhVehicleInfoMaterialPuckDTO>(XhVehicleInfoMaterialPuckDTO.class);
            try {
                puckList = util.importExcel(file.getInputStream());
                if (puckList.size() < 1) {
                    return error("上传的表格内无数据");
                }
            } catch (IOException e) {
                throw new ServiceException("导入数据失败");
            }
            for (XhVehicleInfoMaterialPuckDTO puckDTO : puckList) {
                XhVehicleInfoMaterial material = convertToMaterialInfo(puckDTO, vehicleId, type);
                material.setCreateTime(DateUtils.getNowDate());
                list.add(material);
            }
        } else {
            throw new ServiceException("导入数据失败,传入的type错误:" + type);
        }

        return success(xhVehicleInfoMaterialService.importMaterial(list));
    }

    private XhVehicleInfoMaterial convertToMaterialInfo(Object dto, String vehicleId, String type) {
        XhVehicleInfoMaterial materialInfo = new XhVehicleInfoMaterial();
        BeanUtils.copyProperties(dto, materialInfo);
        materialInfo.setVehicleId(Long.parseLong(vehicleId));
        materialInfo.setType(type);
        materialInfo.setDelFlag("0");
        return materialInfo;
    }

}
